//
//  MKAPITaskTestCase.m
//  MKAPITests
//
//  Created by 苏尚进 on 2022/7/25.
//  Copyright © 2022 moon. All rights reserved.
//

#import "MKAPITaskTestCase.h"
#import "NSTimer+MKAPITest.h"
#import <MKAPI/MKAPI.h>

@interface _MKTBase1 : MKAPITask
@property(nonatomic,strong) NSTimer *timer;
@end
@implementation _MKTBase1
static NSInteger __shareCount = 0;
+ (NSInteger)totalCount{
    return __shareCount;
}
- (void)doRunTask{
    __shareCount++;
    @MKAPI_WEAKIFY(self);
    self.timer = [NSTimer mkapitest_scheduledTimerWithTimeInterval:0.005 repeats:NO block:^(NSTimer * _Nonnull timer) {
        @MKAPI_NORMALIZE(self);
        NSLog(@"complete base :%@",self);
        [self completeWithError:nil];
    }];
}
- (void)doCancel{
    [self.timer invalidate];
    [self completeWithError:[NSError errorWithDomain:@"MKAPITest" code:MKAPITaskCodeCancel userInfo:@{NSLocalizedDescriptionKey:@"Cancel"}]];
}
+ (void)getResultWithCompletion:(void(^)(NSInteger result,NSError * _Nullable error))completion debugName:(NSString *)name{
    if(!completion)return;
    NSInteger result = [_MKTBase1 totalCount];
    if(result>0){
        completion(result,nil);
    }else{
        [[MKAPITaskSession sharedSession] getTasksWithTaskClass:self completion:^(NSArray<__kindof MKAPITask *> * _Nonnull tasks) {
            NSLog(@"begin get base api:%@",name);
            _MKTBase1 *baseApi = tasks.firstObject;
            NSLog(@"api:%@,base api:%@",name,baseApi);
            if(!baseApi){
                baseApi = [[_MKTBase1 alloc] init];
                [NSThread sleepForTimeInterval:0.01];
                [baseApi run];
            }
            [NSThread sleepForTimeInterval:0.01];
            [baseApi addCompletionHandler:^(__kindof MKAPITask * _Nonnull task, BOOL success, NSError * _Nullable error) {
                completion([_MKTBase1 totalCount],error);
            }];
            NSLog(@"end get base api:%@",name);
        }];
    }
}
@end
@interface _MKTApi : MKAPITask
@property(nonatomic,strong) NSTimer *timer;
@property(nonatomic,assign) NSInteger runCount;
@property(nonatomic,strong) NSString *name;
@end
@implementation _MKTApi
- (void)willBeginRunning{
    [NSThread sleepForTimeInterval:0.01];
    [super willBeginRunning];
}
- (void)doRunTask{
    self.runCount++;
    dispatch_queue_t queue = dispatch_queue_create([[NSString stringWithFormat:@"testApi_%@",self.name] UTF8String], nil);
    dispatch_async(queue, ^{
        NSLog(@"begin run api:%@",self.name);
        [_MKTBase1 getResultWithCompletion:^(NSInteger result, NSError * _Nullable error) {
            if(error){
                [NSThread sleepForTimeInterval:0.01];
                [self completeWithError:error];
            }else{
                @MKAPI_WEAKIFY(self);
                dispatch_async(dispatch_get_main_queue(), ^{
                    self.timer = [NSTimer mkapitest_scheduledTimerWithTimeInterval:1 repeats:NO block:^(NSTimer * _Nonnull timer) {
                        @MKAPI_NORMALIZE(self);
                        [self completeWithError:nil];
                    }];
                });
            }
        } debugName:self.name];
        NSLog(@"end run api:%@",self.name);
    });
}
- (void)doCancel{
    [self.timer invalidate];
    [self completeWithError:[NSError errorWithDomain:@"MKAPITest" code:MKAPITaskCodeCancel userInfo:@{NSLocalizedDescriptionKey:@"Cancel"}]];
}
@end

@interface _MKTApi2 : MKAPITask
@property(nonatomic,strong) NSTimer *timer;
@property(nonatomic,assign) NSInteger runCount;
@property(nonatomic,strong) NSString *name;
@end
@implementation _MKTApi2
- (void)willBeginRunning{
    [NSThread sleepForTimeInterval:0.01];
    [super willBeginRunning];
}
- (void)doRunTask{
    self.runCount++;
    @MKAPI_WEAKIFY(self);
    self.timer = [NSTimer mkapitest_scheduledTimerWithTimeInterval:1 repeats:NO block:^(NSTimer * _Nonnull timer) {
        @MKAPI_NORMALIZE(self);
        [self completeWithError:nil];
    }];
}
- (void)doCancel{
    [self.timer invalidate];
    [self completeWithError:[NSError errorWithDomain:@"MKAPITest" code:MKAPITaskCodeCancel userInfo:@{NSLocalizedDescriptionKey:@"Cancel"}]];
}
@end
@implementation MKAPITaskTestCase

- (void)setUp {
    // Put setup code here. This method is called before the invocation of each test method in the class.
}

- (void)tearDown {
    // Put teardown code here. This method is called after the invocation of each test method in the class.
}
- (void)testConcurrencyRun_Dependance{//并发测试
    NSMutableArray *eList = [[NSMutableArray alloc] init];
    for (int i=0; i<20; i++) {
        XCTestExpectation *e1 = [self expectationWithDescription:[NSString stringWithFormat:@"testConcurrency:%@",@(i)]];
        [eList addObject:e1];
        _MKTApi *api = [[_MKTApi alloc] init];
        api.name = [@(i) description];
        [api addCompletionHandler:^(__kindof MKAPITask * _Nonnull task, BOOL success, NSError * _Nullable error) {
            NSInteger totalCount = [_MKTBase1 totalCount];
            if(totalCount==1){
                [e1 fulfill];
            }else{
                NSLog(@"totalCount:%@",@(totalCount));
            }
        }];
        [api run];
    }
    [self waitForExpectations:eList timeout:20];
}
- (void)testConcurrencyRun_RepeatRun{
    _MKTApi2 *api = [[_MKTApi2 alloc] init];
    api.name = [@(0) description];
    XCTestExpectation *e1 = [self expectationWithDescription:[NSString stringWithFormat:@"RepeatRun:%@",@(0)]];
    [api addCompletionHandler:^(__kindof _MKTApi2 * _Nonnull task, BOOL success, NSError * _Nullable error) {
        if(api.runCount==1){
            [e1 fulfill];
        }else{
            NSLog(@"runCount:%@",@(task.runCount));
        }
    }];
    for (int i=0; i<10; i++) {
        dispatch_queue_t queue = dispatch_queue_create([[NSString stringWithFormat:@"testApi2_%@",@(i)] UTF8String], nil);
        dispatch_async(queue, ^{
            [api run];
            [api run];
        });
    }
    [self waitForExpectations:@[e1] timeout:5];
}
- (void)testTaskTimeout{
    NSMutableArray *eList = [[NSMutableArray alloc] init];
    {
        XCTestExpectation *e1 = [self expectationWithDescription:@"timeoutExpection1"];
        MKAPITask *api = [[MKAPITask alloc] init];
        api.timeoutDuration = 1;
        [api addCompletionHandler:^(__kindof MKAPITask * _Nonnull task, BOOL success, NSError * _Nullable error) {
            if(error.mkapi_isTaskTimeout){
                [e1 fulfill];
            }
        }];
        [api run];
        [eList addObject:e1];
    }
    {
        XCTestExpectation *e1 = [self expectationWithDescription:@"timeoutExpection2"];
        MKAPITask *api = [[MKAPITask alloc] init];
        api.timeoutDuration = 1;
        [api addCompletionHandler:^(__kindof MKAPITask * _Nonnull task, BOOL success, NSError * _Nullable error) {
            if(success||!error.mkapi_isTaskTimeout){
                [e1 fulfill];
            }
        }];
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [api completeWithError:nil];
        });
        [api run];
        [eList addObject:e1];
    }
    {
        XCTestExpectation *e1 = [self expectationWithDescription:@"timeoutExpection3"];
        MKAPITask *api = [[MKAPITask alloc] init];
        api.timeoutDuration = 1;
        [api addCompletionHandler:^(__kindof MKAPITask * _Nonnull task, BOOL success, NSError * _Nullable error) {
            if(success||!error.mkapi_isTaskTimeout){
                [e1 fulfill];
            }
        }];
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [api cancel];
            [api completeWithError:[NSError mkapi_errorWithCancelTask:api]];
        });
        [api run];
        [eList addObject:e1];
    }
    
    
    [self waitForExpectations:eList timeout:2];
}
@end
